#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.utils import simplejson
from dajaxice.decorators import dajaxice_register
from documents.models import Document, ModuleTerm, ModulePart, Module, Lecturer, Item

import logging
from documents.formfields import FullNameField
import re
from documents.helper import natsort

# Get an instance of a logger
logger = logging.getLogger('dajaxice')

"""
Give a list of similar names of this type of module_part by:
intelligent autocomplete system will provide useful names
by taking all names in the following priority:
1. Suggest the names of this exact ModulePart
2. Suggest the names of other ModuleParts with the same title
2.1. of the same lecturer
2.2. in general

TODO: Since we detect same beginnings: Use the same beginnings and
    if there is a number append its increment
"""
@dajaxice_register
def document_name_suggestions(request, module_part_id, module_term_id, name):
    module_part = ModulePart.objects.get(id = module_part_id)
    module_term = ModuleTerm.objects.get(id = module_term_id)
    
    documents = Document.objects.filter(name__istartswith = name).order_by('name')
    
    module_term_documents = documents.filter(module_term = module_term)
    
    module_part_lecturer_like_documents = documents.filter(module_part__name = module_part.name, module_term__lecturer = module_term.lecturer)
    
    documents = documents.exclude(module_term__lecturer = module_term.lecturer)
    
    module_part_documents = module_part.document_set.all()
    
    documents = documents.exclude(module_part = module_part)
    
    module_part_like_documents = documents.filter(module_part__name = module_part.name)
    
    
    module_term_document_names = map(lambda x: x['name'], module_term_documents.values('name'))
    
    module_part_lecturer_like_document_names = map(lambda x: x['name'], module_part_lecturer_like_documents.values('name'))
    module_part_document_names = map(lambda x: x['name'], module_part_documents.values('name'))
    module_part_like_document_names = map(lambda x: x['name'], module_part_like_documents.values('name'))
    
    module_term_document_names = _suggest_names(module_term_document_names)
    
    module_part_lecturer_like_document_names = _drop_similar_strings(module_part_lecturer_like_document_names)
    
    module_part_document_names = _drop_similar_strings(module_part_document_names)
    
    module_part_like_document_names = _drop_similar_strings(module_part_like_document_names)
    
    result = []
    
    for i in range(min(3, (len(module_term_document_names)))):
        result.append(module_term_document_names[i])
    
    # TODO: also append new stuff
    if len(module_term_document_names) < 1:
        for i in range(min(3, (len(module_part_document_names)))):
            result.append(module_part_document_names[i])
        
        for i in range(min(4, (len(module_part_lecturer_like_document_names)))):
            result.append(module_part_lecturer_like_document_names[i])
        
        for i in range(min(2, (len(module_part_like_document_names)))):
            result.append(module_part_like_document_names[i])
        
    result = _drop_same_strings(sorted(result))
    
    return simplejson.dumps({'suggestions': result})


def _suggest_names(module_part_document_names):
    """
    If a name contains numbers and there are many: only return one of those with the numbers incremented by one
    """
    # sort the list so that the biggest number is at the end
    splitted_module_part_document_names = map(_split_name, module_part_document_names)
    splitted_module_part_document_names.sort()
    
    splitted_result = []
    last = None
    for splitted_name in splitted_module_part_document_names:
        # if there is a new entry
        if last and (not _chars_equal(last, splitted_name)):
            splitted_result.append(last)
        last = splitted_name
    
    if last:
        splitted_result.append(last)
        
    result = []
    for splitted_name in splitted_result:
        # append the last given item with all numbers incremented by 1 => better suggestions for documents
        inc_splitted_name = map( lambda x: x + 1 if isinstance( x, ( int, long ) ) else x, splitted_name )
        # create a string from the split lists and append
        result.append( reduce( lambda x, y: x.__str__() + y.__str__(), inc_splitted_name ) )
    
    return result

def _split_name(name):
    """
    Creates a list with the name splitted into digit elements and non digit elements
    """
    return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', name)]

            
def _chars_equal(first, second):
    """
    Check wether the character parts in the lists in 2 lists are equal
    """
    if len(first) != len(second):
        return False;
    
    for first_part, second_part in zip(first, second):
        if not isinstance( first_part, ( int, long ) ) and first_part != second_part:
            return False
    
    return True
            
def _drop_same_strings(strings):
    result = []
    
    laststring = ''
    for string in strings:
        if not laststring == string:
            result.append(string)
        laststring = string
    return result
            
def _drop_similar_strings(strings):
    result = []
    
    laststring = ''
    for string in strings:
        if not (_have_n_same_start_letters(laststring.lower(), string.lower(), 4)):
            result.append(string)
        laststring = string
    return result

def _have_n_same_start_letters(a, b, n):
    if len(a) < n or len(b) < n:
        return False
     
    for i in range(n):
        if not(a[i] == b[i]):
            return False
    return True


"""
Give a list of suggestions of lecturers starting like the param lecturer_name

TODO: Prioritise:
1. lecturers who already lectured this module
2. lecturers of this faculty
3. everyone else

@param lecturer_name: name of the leturer so far
@return: suggestions of lecturers corresponding to te beginning
"""
@dajaxice_register
def lecturer_name_suggestions(request, module_id, lecturer_name):
    # seperate the lecturer
    (first_name, last_name) = FullNameField.seperate_full_name(lecturer_name)
    
    lecturers = Lecturer.objects.filter(last_name__istartswith = last_name, first_name__istartswith = first_name).order_by('last_name', 'first_name')
    
    lecturer_names = map(lambda x: x['last_name'] + ', ' + x['first_name'], lecturers.values('last_name', 'first_name'))
    
    return simplejson.dumps({'suggestions': lecturer_names})


"""
Give a list of suggestions of module_parts starting like the param name

TODO: Prioritise: Faculty

@param name: name of the module_part so far
@return: suggestions of module_parts corresponding to the beginning
"""
@dajaxice_register
def module_part_suggestions(request, module_id, name):
    module = Module.objects.get(id = module_id)
    
    module_parts = ModulePart.objects.filter(name__istartswith = name, module__faculty = module.faculty).order_by('name')
    
    duplicate_module_part_names = map(lambda x: x['name'], module_parts.values('name'))

    # clean duplicates from the list (works this way since it is ordered by the name)
    module_part_names = []
    for name in duplicate_module_part_names:
        if (len(module_part_names) == 0) or (module_part_names[-1] != name):
            module_part_names.append(name)
    
    return simplejson.dumps({'suggestions': module_part_names})

"""
Give a list of suggestions of item_category

@param name: name of the item_category so far
@return: suggestions of item_category corresponding to the beginning
"""
@dajaxice_register
def item_category_suggestions(request, module_part_id, module_term_id, item_category_name):
    module_part = ModulePart.objects.get(id = module_part_id)
    
    items = Item.objects.filter(item_category__istartswith = item_category_name).order_by('item_category').exclude(item_category = '')
    
    preferred_suggestions = items.filter(document__module_part = module_part)
    rest_suggestions = items.exclude(document__module_part = module_part)
    
    duplicate_item_category_names = map(lambda x: x['item_category'], preferred_suggestions.values('item_category'))
    duplicate_item_category_names.extend(map(lambda x: x['item_category'], rest_suggestions.values('item_category')))
    
    # clean duplicates from the list (works this way since it is ordered by the name)
    item_category_names = []
    for item_category in duplicate_item_category_names:
        if (len(item_category_names) == 0) or (item_category_names[-1] != item_category):
            item_category_names.append(item_category)
    
    return simplejson.dumps({'suggestions': item_category_names})